package com.bridge.aspect;

import com.alibaba.fastjson.JSONObject;
import com.bridge.annotion.DictEscapeValue;
import com.bridge.annotion.DictResponse;
import com.bridge.utils.PageUtil;
import com.bridge.utils.ResUtils;
import com.bridge.vo.DictResponseData;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.CtClass;
import org.apache.ibatis.javassist.CtField;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * @author bridge
 * @Date 2022/07/10/22:17
 */
@Slf4j
@Aspect
@Component
public class DictResponseAspectCglib {

    /**
     * 转义后缀
     */
    private static final String SUFFIX = "dictTag";

    /**
     * 包名
     */
    private static final String REGEX_PACKAGE = "com.bridge.*.*";

    /**
     * list集合
     */
    private static final String LIST = "java.util.List";

    /**
     * set集合
     */
    private static final String SET = "java.util.Set";

    /**
     * 处理返回结果
     *
     * @param joinpoint    切点
     * @param dictResponse 注解
     * @param result       结果
     * @return
     */
//    @AfterReturning(value = "@annotation(dictResponse)", returning = "result")
    public Object after(JoinPoint joinpoint, DictResponse dictResponse, Object result) throws Exception {
        String method = joinpoint.getSignature().toString();
        log.info("解析注入JSON数据,method:{} start============>", method);
        long start = System.currentTimeMillis();
        processResult(result);
        long end = System.currentTimeMillis();
        log.info("解析注入JSON数据 ,method:{} 耗时:{} ms end============>", method, (end - start));
        return result;
    }


    /**
     * 处理结果
     *
     * @param result result
     */
    private void processResult(Object result) throws Exception {
        Object data = ((ResUtils<?>) result).getData();
        if (data == null) {
            return;
        }
        if (data instanceof Collection) {
            processData(data);
        } else if (data instanceof PageUtil) {
            processData(((PageUtil<?>) data).getList());
        } else {
            List<Object> list = new ArrayList<>();
            list.add(data);
            processData(data);
        }
    }

    /**
     * 处理返回数据
     *
     * @param data data
     * @return
     */
    private void processData(Object data) throws Exception {
        //获取数据字典
        Map<String, Map<String, String>> dicEnumMap = getDicEnumMap();
        log.info("json format start============>");
        long start2 = System.currentTimeMillis();
        // 第一层
        for (Object recordData : (Collection<?>) data) {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.get(recordData.getClass().getName());
            // 注意: 不能用pool.get(Student.class.getName())，否则报错attempted  duplicate class definition for name，原因是同个Class不能在同个ClassLoader中加载两次
            Field[] fields = recordData.getClass().getDeclaredFields();
            for (Field field : fields) {//遍历对象的属性和值 属性和值一一对应
                field.setAccessible(true);//开启对象的属性访问权和修改权
                // 获取类型
                String type = field.getType().getName();
                String name = field.getName();
                if (type.matches(REGEX_PACKAGE) && !type.matches("com.bridge.enums.*")) {
                    Field[] fields2 = field.getClass().getDeclaredFields();
                    for (Field field2 : fields2) {//遍历对象的属性和值 属性和值一一对应
                        field2.setAccessible(true);
                        String value = field.get(field.getClass()) + "";
                        formatAnnotationValue(field2, value, dicEnumMap);
                    }
                } else if (LIST.equals(type) || SET.equals(type)) {
                    for (Object recordData2 : (Collection<?>) field.get(recordData)) {
                        Field[] fields2 = recordData2.getClass().getDeclaredFields();
                        for (Field field2 : fields2) {//遍历对象的属性和值 属性和值一一对应
                            field2.setAccessible(true);
                            String value = field.get(field.getClass()) + "";
                            formatAnnotationValue(field2, value, dicEnumMap);
                        }
                    }
                } else {
                    field.setAccessible(true);
                    String value = field.get(recordData) + "";
                    String dicValue = formatAnnotationValue(field, value, dicEnumMap);
                    if(StringUtils.hasText(dicValue)){
                        // 创建新字段
                        CtField ctField = new CtField(pool.get(type), name+SUFFIX, ctClass);
                        ctField.setModifiers(Modifier.PRIVATE);
                        ctClass.addField(ctField,dicValue);
                    }
                }
            }
        }
        long end2 = System.currentTimeMillis();
        log.info("json format  end=== interval:{} ms=========>", (end2 - start2));
    }

    public String  formatAnnotationValue(Field field, String value, Map<String, Map<String, String>> dicEnumMap) throws IllegalAccessException {
        if (field.getAnnotation(DictEscapeValue.class) == null) {
            return value;
        }
        String dickey = field.getAnnotation(DictEscapeValue.class).type();
        return translateDicKeyValue(dicEnumMap, dickey, value);
    }


    /**
     * 获取数据字典的值 （公司项目查询数据库）
     *
     * @return
     */
    private Map<String, Map<String, String>> getDicEnumMap() {
        Map<String, Map<String, String>> dicEnumMap = new HashMap<>();
        Map<String, String> map1 = new HashMap<>();
        map1.put("admin", "admin的dict");
        map1.put("zhangshan", "zhangshan的dict");
        Map<String, String> map2 = new HashMap<>();
        map2.put("管理员", "管理员Dict");
        map2.put("张三", "张三Dict");
        dicEnumMap.put("user_name", map1);
        dicEnumMap.put("nick_name", map2);
        return dicEnumMap;
    }


    /**
     * json格式化
     *
     * @param dicEnumMap dicEnumMap
     * @param data       data
     * @param jsonObject jsonObject
     */
    private void formatJsonObject(Map<String, Map<String, String>> dicEnumMap, DictResponseData data,
                                  JSONObject jsonObject) {

        if (data == null || jsonObject == null || CollectionUtils.isEmpty(data.getSubList())) {
            return;
        }
        for (DictResponseData dictResponseData : data.getSubList()) {
            if (dictResponseData.isIfAnnotation()) {
                String value = jsonObject.getString(dictResponseData.getRstFiled());
                String textValue = this.translateDicKeyValue(dicEnumMap, dictResponseData.getDicKey(), value);
                jsonObject.put(dictResponseData.getRstFiled() + SUFFIX, textValue);
            }

        }

    }


    private String translateDicKeyValue(Map<String, Map<String, String>> dicEnumMap, String type, String key) {
        if (!StringUtils.hasText(type) || !StringUtils.hasText(key)
                || CollectionUtils.isEmpty(dicEnumMap)) {
            return "";
        }

        Map<String, String> dicMap = dicEnumMap.get(type);
        if (CollectionUtils.isEmpty(dicMap)) {
            return "";
        }
        return dicMap.get(key);
    }


}
